﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.IO;

namespace Tomato.Cryptography
{
    class SymmetricEncryption
    {
        public SymmetricEncryption(SymmetricAlgorithm algorithm)
        {
            this.algorithm = algorithm;
            algorithm.Mode = CipherMode.CBC;
        }

        private SymmetricAlgorithm algorithm;


        public Key Key { get; set; }


        public void Encrypt(Stream messageStream, Stream encryptionStream)
        {
            ICryptoTransform transform = algorithm.CreateEncryptor(Key.GetKey(algorithm.BlockSize), Key.GetIV(algorithm.BlockSize));
            CryptoStreamMode mode = CryptoStreamMode.Write;

            CryptoStream cryptoStream = new CryptoStream(encryptionStream, transform, mode);

            while (true)
            {
                int b = messageStream.ReadByte();
                if (b == -1)
                {
                    break;
                }

                cryptoStream.WriteByte((byte)b);
            }
            
            cryptoStream.FlushFinalBlock();
        }

        public string EncryptAsBase64(string s)
        {
            using (MemoryStream sourceStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(s)))
            {
                using (MemoryStream targetStream = new MemoryStream())
                {
                    Encrypt(sourceStream, targetStream);
                    return Convert.ToBase64String(targetStream.GetBuffer(), 0, (int)targetStream.Length, Base64FormattingOptions.None);
                }
            }
        }


        public void Decrypt(Stream encryptionStream, Stream messageStream)
        {
            ICryptoTransform transform = algorithm.CreateDecryptor(Key.GetKey(algorithm.BlockSize), Key.GetIV(algorithm.BlockSize));
            CryptoStreamMode mode = CryptoStreamMode.Read;

            CryptoStream cryptoStream = new CryptoStream(encryptionStream, transform, mode);

            while (true)
            {
                int b = cryptoStream.ReadByte();
                if (b == -1)
                {
                    break;
                }

                messageStream.WriteByte((byte)b);
            }
        }

        public string DecryptFromBase64(string s)
        {
            using (MemoryStream sourceStream = new MemoryStream(Convert.FromBase64String(s)))
            {
                using (MemoryStream targetStream = new MemoryStream())
                {
                    Decrypt(sourceStream, targetStream);
                    return System.Text.Encoding.UTF8.GetString(targetStream.GetBuffer(), 0, (int)targetStream.Length);
                }
            }
        }
    }
}
